<?php
/**
 * Created by PhpStorm.
 * User: eValor
 * Date: 2019-03-20
 * Time: 16:57
 */

namespace App\GameService;

use App\Enum\SysEnum;
use App\Model\User;
use App\WebSocket\WsBase;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use App\Common\BaseComm;
use App\Enum\CardEnum;
use App\Model\GameType;
use App\Utility\RedisTools;
use Swoole\Timer;
use App\GameService\games\PlayHelp;
use App\Common\GameCommon;
use App\Model\GameRobot as RobotModel;

/**
 * 简单机器人操作
 */
class Gamerobot extends WsBase
{
    
    protected $allowGameIds = [105];
    
    /**
     * TODO 机器人玩家介入操作
     * @return boolean
     */
    public function play()
    {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameOObject = $this->paramsBean->getGameObject();
        BaseEnum::Logger('实例化：整体 (getGameObject)---playNewGame >>>' . json_encode($gameOObject), 'user-login');
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        if (!$gameRId) {
            $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失");
            return true;
        }
        $steps = CardEnum::GAME_BRNN_STEP;
        $seatEmpty = ['seat1' => 0, 'seat2' => 0, 'seat3' => 0, 'seat4' => 0];
        $mainInfo = ["name" => '10***8', "sex" => 1, 'head_id' => 2, "points" => 0];
        $lastResult = ["gstart" => 1, "gameNo" => null, "status" => 0, "player" => null, "mainInfo" => $mainInfo, "roomInfo" => null, "lists" => null];
        $playerInfo = $userid = FALSE; // 玩家登录信息
        try {
            $this->userIsOnline($loginFd, $playerInfo, $userid);  
        } catch (\Throwable $e) {
            return false;
        }

        $roomSeatLimits = FALSE; //房间每个位置限红

        // 获取在线的游戏列表数据；
        try {
            $gameModel = new GameType();
            $gRoomInfo = $gameModel->getGameRoomDetail($gameRId); // 获取房间详细参数
            $gameID = isset($gRoomInfo["gameId"]) ? intval($gRoomInfo["gameId"]) : 0;
            $gameName = isset($gRoomInfo["gpKey"]) ? $gRoomInfo["gpKey"] : "";
            $roomLastPots = isset($gRoomInfo["smallPoints"]) ? floatval($gRoomInfo["smallPoints"]) : 0;         // 房间的携带分要求；
            $roomEveryPots = isset($gRoomInfo["everyPoints"]) ? floatval($gRoomInfo["everyPoints"]) : 0;        // 房间底分
            if (empty($gRoomInfo) || $gameID <= 0 || !in_array($gameID, $this->allowGameIds, TRUE)) {
                throw new \Exception("获取房间信息异常", BaseEnum::MSG_0XF6);
            }

            //生成筹码
            $selectChips = GameCommon::getRoomsChips($gameRId, $roomEveryPots);

            //房间位置限红值
            $roomSeatLimits = GameCommon::getRoomsLimitBets($gameRId, $roomEveryPots);


            $username = isset($playerInfo["name"]) ? $playerInfo["name"] : "";
            $login_points = isset($playerInfo["points"]) ? floatval($playerInfo["points"]) : 0;

            // 是否准入分
            if ($login_points <= 0 || $login_points < $roomLastPots || $roomEveryPots <= 0) {
                throw new \Exception("玩家游戏分达不到房间最低标准，退出房间!!", BaseEnum::MSG_0XF8);
            }
            // 写入玩家信息
            $newWj = array(
                "uid" => $userid,
                'name' => $username,
                "agentId" => isset($playerInfo['recUid']) ? intval($playerInfo['recUid']) : 0, // 代理用户ID
                "sex" => isset($playerInfo['gender']) ? intval($playerInfo['gender']) : 0, // 性别
                "head_id" => isset($playerInfo['head_url']) ? intval($playerInfo['head_url']) : 0, // 头像
                "fd" => $loginFd,
                "points" => $login_points,
                "notBetCount" => 0
            );

            //TODO  房间内在线玩家列表（加入）
            $wjList = BaseComm::distMemoryPlayer($gameRId, false);
            $wjList[$userid] = $newWj;
            BaseComm::distMemoryPlayer($gameRId, true, $wjList);


            //TODO 前20人排名:
            /* $frontList = $wjList;
            @array_multisort(array_column($frontList,'points'),SORT_DESC,$frontList);
            if(isset($frontList) && !empty($frontList) && sizeof($frontList) > 20){ $frontList = array_slice($frontList, 0,20); } //取前二十名玩家信息 */


            //TODO 开奖结果走势数据推到前端
            $historydata = [];
            $historyWins = PlayHelp::getInstance()->getResultLog($gameRId, 'history');
            if (!empty($historyWins)) {
                foreach ($historyWins as $r => $oneivs) {
                    $historydata[] = ["key" => $r, "data" => $oneivs];
                }
            }

            //TODO  加入房间成功后就删掉当前用户在房间列表的操作；
            $allUserFds = BaseComm::distMemoryFjListUser($gameID, FALSE);
            if (!empty($allUserFds) && isset($allUserFds[$userid])) {
                unset($allUserFds[$userid]);
                BaseComm::distMemoryFjListUser($gameID, TRUE, $allUserFds);   //TODO　写入房间列表FD
            }

            //TODO 游戏房间（首次进来 ｜正在进行中）
            $fjInfo = BaseComm::distMemoryRooms($gameRId, false);
            $fjStatus = isset($fjInfo['fjStatus']) ? intval($fjInfo['fjStatus']) : 0;
            $roomSays = array('gameId' => $gameRId, "everyPoints" => $roomEveryPots, 'smallPoints' => $roomLastPots, "chips" => $selectChips, "history" => $historydata);


            $allWeis = [];

            //正在游戏的房间号
            if (!isset($fjInfo) || empty($fjInfo)) {
                $gameNo = BaseComm::getRoomUnioxNo($gameRId);       //生成房间编号

                //初始化空位置数据
                for ($j = 1; $j <= 4; $j++) {
                    $setk = "seat" . $j;
                    $limits = isset($roomSeatLimits[$setk]) ? $roomSeatLimits[$setk] : FALSE;             //每个位置还要加下下注限红数据
                    $allWeis[] = ["seatNo" => $j, "total" => 0, "min" => $limits['min'] ?? 0, "max" => $limits['max'] ?? 0];
                }
                $gameInfo = array("step" => '', "isCanBet" => 0, "seats" => $allWeis, "seatCards" => []);
                $fjInfo = array(                                    //组装房间的状态信息;
                    "isOpen" => 1,
                    "gameId" => $gameID,
                    'grid' => $gameRId,
                    "gameNo" => $gameNo,
                    "fjStatus" => -1,
                    'create' => time(),
                    "mutdotts" => $seatEmpty,
                    'list' => [],
                );
                $allfdkey = SysEnum::USER_PLAY_FDMAP_KEY;
                RedisTools::Pool_hSet($allfdkey, $userid, json_encode([$gameNo, $gameRId]));  //缓存玩家最近的房间号；
                

                //房间内的数据结构
                BaseComm::distMemoryRooms($gameRId, TRUE, $fjInfo);
                //游戏开始(asycStartGame)
                if (!$gameOObject || empty($gameOObject) || (!empty($gameOObject) && isset($gameOObject->baseGameName) && $gameOObject->baseGameName != $gameName)) {
                    $gameOObject = BaseEnum::getClassObject($gameName, false);           // 创建对象；
                    BaseEnum::Logger('实例化为空：新实例化一个操作；-->>>' . json_encode(['gName' => $gameName, "obj" => $gameOObject]), 'user-login');
                }
                if (!empty($gameOObject)) {
                    BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . json_encode($gameOObject), 'user-login');
                    if (!empty($gameOObject) && method_exists($gameOObject, "asycStartGame")) {

                        // 启动游戏操作
                        $gameOObject->setGameStatus("P-" . CardEnum::GAME_STEP_0); // 设置游戏状态；
                        BaseEnum::Logger('实例化对象：' . json_encode($gameOObject), 'user-login');
                        BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . $fjInfo['gameNo'], 'user-login');

                        Timer::after(1000, function () use ($gameNo, $gameRId, $fjInfo, $gameOObject) {
                            //房间ID
                            $gameOObject->asycStartGame($gameNo, $gameRId, $fjInfo);
                        });
                    }
                } else {
                    BaseEnum::Logger("互动失败：Games-(play)-getClassObject，[{$gameName}]----失败!!!!" . json_encode($gameOObject), 'user-login');
                }
                $lastResult["gstart"] = 1;
                $lastResult["gameNo"] = $gameNo;
                $lastResult['roomInfo'] = $roomSays;
                unset($newWj['notBetCount']);
                $lastResult['player'] = $newWj;
                $lastResult['lists'] = $gameInfo;
                if (!empty($loginFd)) { // 登录玩家通知：
                    $this->ResOK($lastResult, "玩家进入房间成功");
                }

            } else if (isset($fjInfo['gameNo']) && $fjStatus >= 0) {

                $newGameNo = $fjInfo['gameNo'];
                //开局后  玩家再进入就是直接显示游戏数据；
                $lastResult["gstart"] = 1;
                $lastResult["status"] = $fjStatus;
                $lastResult["gameNo"] = $newGameNo;
                $lastResult['roomInfo'] = $roomSays;
                unset($newWj['notBetCount']);
                $lastResult['player'] = $newWj;

                //TODO  桌面下注情况
                $stepName = isset($steps[$fjStatus]) ? $steps[$fjStatus] : '';
                $gameInfo = array("step" => $stepName, "isCanBet" => 0, "seats" => [], "seatCards" => []);
                $allWeis = [];
                if ($fjStatus > 0) {
                    $allSes = (isset($fjInfo['mutdotts']) && !empty($fjInfo['mutdotts'])) ? $fjInfo['mutdotts'] : $seatEmpty;
                    foreach ($allSes as $set => $setmoney) {
                        $limits = isset($roomSeatLimits[$set]) ? $roomSeatLimits[$set] : FALSE;             //每个位置还要加下下注限红数据
                        $allWeis[] = ["seatNo" => intval(substr($set, -1)), "total" => $setmoney, "min" => $limits['min'] ?? 0, "max" => $limits['max'] ?? 0];
                    }
                    $gameInfo['seats'] = $allWeis;                  //座位信息
                    if ($fjStatus == CardEnum::BR_GAME_STEP_3) {
                        $gameInfo['isCanBet'] = 1;                 //牌的数据；
                    }
                    if ($fjStatus == CardEnum::BR_GAME_STEP_5) {
                        $gameInfo['seat_cards'] = PlayHelp::getInstance()->getRoomCards($newGameNo);  //每个位置的发牌数据
                    }
                }
                $lastResult['lists'] = $gameInfo;
                $this->ResOK($lastResult, "游戏进行中[{$stepName}]");  //正常游戏中(观望状态)；
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("玩家上桌失败：" . $e->getMessage(), 'user-login');
            $this->ResError($e->getCode(), "匹配结果：" . $e->getMessage(), 0); // 普通错误
        }
        return true;

    }


    /**人编号即可（或机器密钥）
     * TODO 机器人登录属于自动分配类型：自动注册(不超最大限人数)
     * TODO 验证机器
     */
    public function login() {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $robotId = isset($data['robotId']) ? intval($data['robotId']) : 0 ;     //机器人ID值
        $stamp = isset($data['timestamp']) ? intval($data['timestamp']) : 0 ; //时间
        $signKey = isset($data['key']) ? strval($data['key']) : '';

        BaseEnum::Logger('机器人登录：初始化 (login)---user >>>' . json_encode($data), 'user-login');
        if(!$robotId || intval($robotId) <= 0 || !$stamp || empty($data)){
            $this->ResError(BaseEnum::MSG_0XF2, "参数丢失");
            return false;
        }

        try {
            //TODO 验证签名成功后
            if (!$this -> checkRobotUser($robotId,$data)) {
                $this->ResError(BaseEnum::MSG_0XF2, "非法操作",SysEnum::RETURN_MSG_LEVEL_1);
                return false;
            }

            $playUid = 0;
            //TODO 查询是否有离线机器人(离线中)
            $freeUser = $this-> getFreeUser($robotId,$playUid);
            BaseEnum::Logger('查询空闲机器人 (login)---robot >>>' . json_encode($freeUser), 'user-login');

            //TODO 机器人自动创建玩家用户
            if (!$freeUser) {

                //创建机器人新玩家
                $freeUser = $this->createRobotUser($robotId,$playUid);
                BaseEnum::Logger('创建机器人 (login)---robot >>>' . json_encode($freeUser), 'user-login');
            }

            if (!$playUid && intval($playUid) <= 0) {
                $this->ResError(BaseEnum::MSG_0XF2, "机器人超限",SysEnum::RETURN_MSG_LEVEL_1);
                return false;
            }

            //执行登录
            $loginReturn  = $this->loginToGame($robotId,$freeUser,$loginFd);
            if(isset($loginReturn) && !empty($loginReturn)){
                //加入机器人列表 ==== [游戏匹配：做准备中]
                $this->joinGameRobotList($robotId,$freeUser,$loginFd);
                $this->ResOK($loginReturn,"成功");
                return TRUE;
            }else{
                $this->ResError(BaseEnum::MSG_0XF2, "登录失败",SysEnum::RETURN_MSG_LEVEL_3);
                return true;
            }
        } catch (\Throwable $e) {
            $this->ResError($e->getCode(), $e->getMessage());
        }
        return false;
    }


    //TODO 机器人身份验证
    protected function checkRobotUser($robotId,$data){
        $stamp = isset($data['timestamp']) ? intval($data['timestamp']) : 0 ; //时间
        $signKey = isset($data['key']) ? strval($data['key']) : '';

        $robotModel = new RobotModel();
        $robotClient = $robotModel->getRedisRobotClient($robotId);
        $md5Key = isset($robotClient['md5Key']) ? $robotClient['md5Key'] : '';
        if(empty($md5Key)){
            return false;
        }
        $newKey = BaseEnum::MD5($md5Key,"{$robotId}{$stamp}");
        BaseEnum::Logger('验签：GameRobot--->>>' . json_encode($newKey), 'user-login');
        if($signKey || $signKey == $newKey){
            return true;
        }
        return false;
    }

    //TODO 查询是否有空闲机器人(离线中)
    protected function getFreeUser($robotId,&$playUid) {
        $robotModel = new RobotModel();
        $freeUser = $robotModel->getFreeUser($robotId,$playUid);
        return $freeUser;
    }


    //TODO 创建机器人新玩家
    protected function createRobotUser($robotId,&$playUid) {
        $robotModel = new RobotModel();
        $robotUser = $robotModel->createRobotUser($robotId,$playUid);
        return $robotUser;
    }

    //TODO 登录进入
    protected function loginToGame($robotId,$freeUser,$loginFd) {
        if ($robotId<=0 || empty($freeUser) || $loginFd<=0){
            return false;
        }
        $uid = $freeUser['uid'];
        $userInfo= [
            'uid' => $uid,
            'name'=> $freeUser['name'],
            'group_id' => $freeUser['group_id'],
            'status' => $freeUser['status'],
            'recUid' => $freeUser['recUid'],
            'recUser'=> $freeUser['recUser'],
            'ancestor_ids'=>$freeUser['ancestor_ids'],
            'level' => $freeUser['level'],
            'realname' => $freeUser['realname'],
            'gender'=> $freeUser['gender'],
            'user_ident'=> $freeUser['user_ident'],
            'head_url' => $freeUser['head_url'],
            'points' => $freeUser['points'],
            'reg_ip' => $freeUser['reg_ip'],
            'fd' => $loginFd,
            'lastActiveTime' => time(),
            'onlineStatus' => 1,
            'onStatus' => 'ONLINE',
            'token' => BaseComm::createToken($uid)
        ];
        //覆盖一个旧值会返回0
        RedisTools::Pool_set(SysEnum::USER_LOGIN_REDIS_KEY.$uid,json_encode($userInfo),7200);
        RedisTools::Pool_hSet(SysEnum::getLoginFdMapKey(),"login_".$loginFd , $uid.'-'. $userInfo["token"]);
        return [
            "uid"=>$userInfo['uid'],
            "fd"=>$loginFd,
            "group_id"=> $userInfo["group_id"],
            "name"=>$userInfo['name'],
            "real_name"=>isset($userInfo['realname']) ? $userInfo['realname'] : "",
            "points"=> $userInfo['points'],
            "token"=>$userInfo["token"],
            "sex"=> isset($userInfo["gender"]) ? intval($userInfo["gender"]) : 0,
            "head_id"=> isset($userInfo["head_url"]) ? intval($userInfo["head_url"]) : 1,
        ];
    }

    //TODO 加入机器人列表
    protected function joinGameRobotList($robotId,$freeUser,$loginFd) {
        if ($robotId<=0 || empty($freeUser) || $loginFd<=0){
            return false;
        }
        $field = $freeUser['uid'];
        $value = [
            'uid' => $freeUser['uid'],
            'agentId' => $freeUser['recUid'],
            'name' => $freeUser['name'],
            'loginFd' => $loginFd,
            'gender' => $freeUser['gender'],
            'head_url' => $freeUser['head_url'],
            'points' => $freeUser['points'],
            'playFlag' => 2
        ];
        //TODO 缓存机器人列表和在线机器人列表
        RedisTools::Pool_hSet(SysEnum::getRobotClientKey(),$field,json_encode($value));
        RedisTools::Pool_hSet(SysEnum::ROBOT_ONLINEPLAYER_KEY,$field,1);
        BaseEnum::Logger('加入机器人列表joinGameRobotList--->>>' . json_encode($value), 'user-login');
        return true;
    }

    /**
     * TODO 机器人登出下线
     */
    public function loginout() {
        $error = '';
        $data = $this->paramsBean->getData(true);
        $loginFd = $this->paramsBean->getFd();
        BaseEnum::Logger('登出机器人：Request Data：' . json_encode($data), 'user-login');
        try {
            if($loginFd){
                $res = AuthCommon::clearLoginFd($loginFd,$loginUid);
                RedisTools::Pool_hDel(SysEnum::getRobotClientKey(),$loginUid);
                RedisTools::Pool_hSet(SysEnum::ROBOT_ONLINEPLAYER_KEY,$loginUid,2);
                $this->ResOK(1,"登出成功");
            }else {
                $this-> ResError(-1,"系统异常");
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger($e->getMessage(), 'user-login');
            return FALSE;
        }
        return true;
    }

}

